from typing import Any, List, Optional, Dict

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from app.core.security import get_current_active_user
from app.crud.api_config import api_config
from app.crud.sys_config import sys_config
from app.crud.shipment import shipment
from app.db.session import get_db
from app.models.user import SysUsers
from app.schemas.shipment import Shipment, ShipmentCreate, ShipmentUpdate, ShipmentRoute, RoutePoint
from app.services.gps_service import GPSApiService
from app.services.gps_addr_service import GPSAddressService
from app.services.coordinate_service import CoordinateService
from app.tasks.shipment_tasks import process_single_shipment_task
from app.utils.decorators import api_response
from app.utils.response import error_response, pagination_response, success_response
from app.utils.shipment_utils import detect_field_changes, should_validate_device, should_update_coordinates, get_coordinate_update_fields
from app.utils.timezone_util import now_china, localize_datetime
import logging

logger = logging.getLogger(__name__)
router = APIRouter()


@router.get("/shipments")
@api_response
async def read_shipments(
    db: Session = Depends(get_db),
    number_no: Optional[str] = Query(None, description="单号"),
    pickup_warehouse: Optional[str] = Query(None, description="取货仓库"),
    delivery_warehouse: Optional[str] = Query(None, description="卸货仓库"),
    mac_id: Optional[str] = Query(None, description="设备号"),
    status: Optional[int] = Query(None, description="状态"),
    skip: int = Query(0, description="跳过的记录数"),
    limit: int = Query(100, description="返回的记录数"),
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    获取货物追踪记录列表，支持筛选
    """
    shipments = shipment.search(
        db, 
        number_no=number_no,
        pickup_warehouse=pickup_warehouse,
        delivery_warehouse=delivery_warehouse,
        mac_id=mac_id,
        status=status,
        skip=skip, 
        limit=limit
    )
    total = shipment.count(db, 
        number_no=number_no,
        pickup_warehouse=pickup_warehouse,
        delivery_warehouse=delivery_warehouse,
        mac_id=mac_id,
        status=status
    )
    return pagination_response(data=shipments, total=total)


@router.post("/shipments")
@api_response
async def create_shipment(
    *,
    db: Session = Depends(get_db),
    shipment_in: ShipmentCreate,
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    创建新的货物追踪记录
    """
    try:
        # 1. 验证设备号是否存在
        if shipment_in.mac_id:
            device_valid = await _validate_device(db, shipment_in.mac_id)
            if not device_valid['success']:
                return error_response(
                    code=400,
                    message=f"设备验证失败: {device_valid['message']}"
                )
        
        # 2. 获取仓库坐标
        pickup_coords = None
        delivery_coords = None
        
        if shipment_in.pickup_warehouse:
            pickup_result = await _get_warehouse_coordinates(db, shipment_in.pickup_warehouse)
            if pickup_result['success']:
                pickup_coords = pickup_result['coordinates']
            else:
                return error_response(
                    code=400,
                    message=f"取货仓库地址解析失败: {pickup_result['message']}"
                )
        
        if shipment_in.delivery_warehouse:
            delivery_result = await _get_warehouse_coordinates(db, shipment_in.delivery_warehouse)
            if delivery_result['success']:
                delivery_coords = delivery_result['coordinates']
            else:
                return error_response(
                    code=400,
                    message=f"卸货仓库地址解析失败: {delivery_result['message']}"
                )
        
        # 3. 创建货物记录
        created_by = current_user.user_name if current_user else None
        shipment_obj = shipment.create(db, obj_in=shipment_in, created_by=created_by)
        
        # 4. 更新坐标信息
        if pickup_coords or delivery_coords:
            shipment.update_coordinates(
                db,
                id=shipment_obj.id,
                pickup_coordinates=pickup_coords,
                delivery_coordinates=delivery_coords,
                updated_by=created_by
            )
        
        # 5. 启动定时监控任务
        try:
            process_single_shipment_task.delay(shipment_obj.id)
            logger.info(f"已为货物 {shipment_obj.number_no} 启动监控任务")
        except Exception as e:
            logger.warning(f"启动监控任务失败: {str(e)}")
        
        # 重新获取更新后的数据
        updated_shipment = shipment.get(db, id=shipment_obj.id)
        
        return success_response(
            data=updated_shipment,
            message="货物信息创建成功"
        )
        
    except Exception as e:
        logger.error(f"创建货物记录失败: {str(e)}")
        return error_response(
            code=500,
            message=f"创建失败: {str(e)}"
        )


async def _validate_device(db: Session, mac_id: str) -> Dict[str, Any]:
    """验证设备是否存在"""
    try:
        # 获取GPS API配置
        gps_config = api_config.get_by_code(db, code='gpsApi')
        if not gps_config:
            return {
                'success': False,
                'message': '未找到GPS API配置'
            }
        
        # 创建GPS服务
        gps_service = GPSApiService(
            api_url=gps_config.api_url,
            api_user=gps_config.api_user,
            api_pwd=gps_config.api_pwd
        )
        
        # 登录
        login_result = gps_service.login()
        if not login_result['success']:
            return {
                'success': False,
                'message': f"GPS系统登录失败: {login_result['message']}"
            }
        
        # 查找设备
        device_result = gps_service.find_device_by_mac_id(mac_id)
        
        if device_result['success']:
            return {
                'success': True,
                'device_info': device_result['data']
            }
        else:
            return {
                'success': False,
                'message': f"设备 {mac_id} 不存在或无法访问"
            }
            
    except Exception as e:
        logger.error(f"设备验证失败: {str(e)}")
        return {
            'success': False,
            'message': f"设备验证异常: {str(e)}"
        }


async def _get_warehouse_coordinates(db: Session, address: str) -> Dict[str, Any]:
    """获取仓库地址坐标"""
    try:
        # 获取坐标API配置
        coord_config = api_config.get_by_code(db, code='coordinateApi')
        if not coord_config:
            return {
                'success': False,
                'message': '未找到坐标API配置'
            }
        
        # 创建坐标服务
        coordinate_service = CoordinateService(
            api_url=coord_config.api_url,
            token=coord_config.token
        )
        
        # 获取坐标
        result = coordinate_service.get_coordinates_by_address(address)
        
        if result['success']:
            coordinates = coordinate_service.format_coordinates(result['lng'], result['lat'])
            return {
                'success': True,
                'coordinates': coordinates,
                'lat': result['lat'],
                'lng': result['lng']
            }
        else:
            return {
                'success': False,
                'message': result['message']
            }
            
    except Exception as e:
        logger.error(f"获取坐标失败: {str(e)}")
        return {
            'success': False,
            'message': f"坐标获取异常: {str(e)}"
        }


@router.get("/shipments/{shipment_id}")
@api_response
async def read_shipment(
    shipment_id: int,
    db: Session = Depends(get_db),
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    根据ID获取货物追踪记录
    """
    shipment_obj = shipment.get(db, id=shipment_id)
    if not shipment_obj:
        return error_response(code=404, message="货物追踪记录不存在")
    return success_response(data=shipment_obj)


@router.put("/shipments/{shipment_id}")
@api_response
async def update_shipment(
    *,
    db: Session = Depends(get_db),
    shipment_id: int,
    shipment_in: ShipmentUpdate,
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    更新货物追踪记录
    """
    shipment_obj = shipment.get(db, id=shipment_id)
    if not shipment_obj:
        return error_response(
            code=404,
            message="货物追踪记录不存在"
        )
    
    try:
        # 检查版本号（乐观锁）
        if shipment_obj.version != shipment_in.version:
            return error_response(
                code=409,
                message="记录已被其他用户修改，请刷新后重试"
            )
        
        # 检查是否需要验证和更新相关信息
        changes = detect_field_changes(shipment_obj, shipment_in)
        need_device_validation = should_validate_device(changes)
        need_coordinate_update = should_update_coordinates(changes)
        coordinate_fields = get_coordinate_update_fields(changes)
        
        pickup_coords = None
        delivery_coords = None
        
        # 记录变化信息
        if changes['changed_fields']:
            logger.info(f"货物 {shipment_obj.number_no} 字段变化: {changes['changed_fields']}")
        
        # 4. 设备验证
        if need_device_validation:
            logger.info(f"验证设备号变化: {changes['old_values'].get('mac_id')} -> {changes['new_values'].get('mac_id')}")
            device_valid = await _validate_device(db, shipment_in.mac_id)
            if not device_valid['success']:
                return error_response(
                    code=400,
                    message=f"设备验证失败: {device_valid['message']}"
                )
        
        # 5. 坐标获取和更新
        if need_coordinate_update:
            # 获取取货仓库坐标（如果地址发生变化）
            if coordinate_fields['update_pickup']:
                logger.info(f"更新取货仓库坐标: {changes['old_values'].get('pickup_warehouse')} -> {changes['new_values'].get('pickup_warehouse')}")
                pickup_result = await _get_warehouse_coordinates(db, shipment_in.pickup_warehouse)
                if pickup_result['success']:
                    pickup_coords = pickup_result['coordinates']
                else:
                    return error_response(
                        code=400,
                        message=f"取货仓库地址解析失败: {pickup_result['message']}"
                    )
            
            # 获取卸货仓库坐标（如果地址发生变化）
            if coordinate_fields['update_delivery']:
                logger.info(f"更新卸货仓库坐标: {changes['old_values'].get('delivery_warehouse')} -> {changes['new_values'].get('delivery_warehouse')}")
                delivery_result = await _get_warehouse_coordinates(db, shipment_in.delivery_warehouse)
                if delivery_result['success']:
                    delivery_coords = delivery_result['coordinates']
                else:
                    return error_response(
                        code=400,
                        message=f"卸货仓库地址解析失败: {delivery_result['message']}"
                    )
        
        # 6. 更新基本信息
        updated_by = current_user.user_name if current_user else None
        updated_shipment = shipment.update(db, db_obj=shipment_obj, obj_in=shipment_in, updated_by=updated_by)
        
        # 7. 更新坐标信息（如果有变化）
        if pickup_coords or delivery_coords:
            shipment.update_coordinates(
                db,
                id=updated_shipment.id,
                pickup_coordinates=pickup_coords,
                delivery_coordinates=delivery_coords,
                updated_by=updated_by
            )
        
        # 8. 重新获取更新后的完整数据
        final_shipment = shipment.get(db, id=updated_shipment.id)
        
        return success_response(
            data=final_shipment,
            message="货物信息更新成功"
        )
        
    except Exception as e:
        logger.error(f"更新货物记录失败: {str(e)}")
        return error_response(
            code=500,
            message=f"更新失败: {str(e)}"
        )


@router.delete("/shipments/{shipment_id}")
@api_response
async def delete_shipment(
    *,
    db: Session = Depends(get_db),
    shipment_id: int,
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    删除货物追踪记录
    """
    shipment_obj = shipment.get(db, id=shipment_id)
    if not shipment_obj:
        return error_response(code=404, message="货物追踪记录不存在")
    
    shipment_obj = shipment.remove(db, id=shipment_id)
    return success_response(message="删除成功")


@router.get("/shipments/{shipment_id}/route")
@api_response
async def get_shipment_route(
    shipment_id: int,
    db: Session = Depends(get_db),
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    获取货物追踪路线（适配新的查看路线功能）
    """
    shipment_obj = shipment.get(db, id=shipment_id)
    if not shipment_obj:
        raise HTTPException(status_code=404, detail="货物追踪记录不存在")
    
    # 检查状态，只有进行中和已完成的货物才能查看路线
    if shipment_obj.status not in [10, 30]:
        return error_response(
            code=400,
            message=f"当前状态({shipment_obj.status})不支持查看路线，只有进行中或已完成的货物才能查看路线"
        )
    try:
        # 获取GPS API配置
        gps_config = api_config.get_by_code(db, code="gpsApi")
        if not gps_config:
            raise HTTPException(status_code=404, detail="未找到GPS API配置")
        
        # 创建GPS服务实例
        gps_service = GPSApiService(
            api_url=gps_config.api_url,
            api_user=gps_config.api_user,
            api_pwd=gps_config.api_pwd
        )
        
        # 登录GPS服务
        login_result = gps_service.login()
        if not login_result['success']:
            return error_response(
            code=400,
            message=f"GPS服务登录失败: {login_result['message']}"
        )
        # 计算查询时间范围
        current_time = now_china()
        start_time = localize_datetime(shipment_obj.start_time) if shipment_obj.start_time else current_time
        end_time = localize_datetime(shipment_obj.end_time) if shipment_obj.end_time else current_time
        
        # 转换为时间戳
        start_timestamp = int(start_time.timestamp() * 1000)
        end_timestamp = int(end_time.timestamp() * 1000)
        
        # 获取历史轨迹
        result = gps_service.get_device_history_track(
            shipment_obj.mac_id, 
            start_timestamp, 
            end_timestamp
        )
        
        if not result['success']:
            return error_response(
            code=400,
            message=f"获取轨迹失败: {result['message']}"
            )
        
        track_points = result['data']
        
        # 转换为路线点格式
        route_points = []
        for point in track_points:
            route_point = {
                'lat': point['lat'],
                'lng': point['lng'],
                'timestamp': point['timestamp'],
                'speed': point.get('speed', 0),
                'altitude': point.get('altitude'),
                'time': point.get('time'),
                'mileage': point.get('mileage')
            }
            route_points.append(route_point)
        
        return success_response({
            "shipment_id": shipment_id, 
            "points": route_points,
            "total_points": len(route_points),
            "start_time": start_time.isoformat() if start_time else None,
            "end_time": end_time.isoformat() if end_time else None,
            "status": shipment_obj.status
        })
        
    except HTTPException:
         return error_response(
            code=400,
            message=f"获取轨迹失败"
            )
    except Exception as e:
        logger.error(f"获取货物路线失败: {str(e)}")
        return error_response(
            code=400,
            message=f"获取路线失败: {str(e)}"
            )

@router.post("/shipments/{shipment_id}/start-monitor")
@api_response
async def start_shipment_monitor(
    shipment_id: int,
    db: Session = Depends(get_db),
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    手动启动货物监控任务
    """
    shipment_obj = shipment.get(db, id=shipment_id)
    if not shipment_obj:
        return error_response(code=404, message="货物追踪记录不存在")
    
    if shipment_obj.status not in [0, 10]:
        return error_response(
            code=400,
            message=f"当前状态({shipment_obj.status})不支持启动监控"
        )
    
    try:
        # 启动异步监控任务
        task = process_single_shipment_task.delay(shipment_id)
        
        return success_response(
            data={
                'task_id': task.id,
                'shipment_id': shipment_id
            },
            message='监控任务已启动'
        )
        
    except Exception as e:
        logger.error(f"启动监控任务失败: {str(e)}")
        return error_response(code=500, message=f"启动监控失败: {str(e)}")


@router.get("/shipments/stats")
@api_response
async def get_dashboard_stats(
    db: Session = Depends(get_db),
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    获取仪表盘统计数据
    """
    try:
        # 按状态统计货物数量
        total_shipments = shipment.count(db)
        waiting_shipments = shipment.count(db, status=0)  # 未开始
        in_progress_shipments = shipment.count(db, status=10)  # 进行中  
        completed_shipments = shipment.count(db, status=30)  # 完成
        error_shipments = shipment.count(db, status=-10)  # 异常
        
        # API配置状态
        gps_config = api_config.get_by_code(db, code="gpsApi")
        coordinate_config = api_config.get_by_code(db, code="coordinateApi")
        
        return success_response(data={
            'total_shipments': total_shipments,
            'waiting_shipments': waiting_shipments,
            'in_progress_shipments': in_progress_shipments,
            'completed_shipments': completed_shipments,
            'error_shipments': error_shipments,
            'gps_api_configured': gps_config is not None,
            'coordinate_api_configured': coordinate_config is not None
        })
        
    except Exception as e:
        logger.error(f"获取仪表盘统计失败: {str(e)}")
        return error_response(code=500, message=f"获取统计数据失败: {str(e)}")


@router.post("/gps/batch-addresses")
@api_response
async def batch_get_addresses(
    coordinates: List[Dict[str, float]],
    db: Session = Depends(get_db),
    current_user: SysUsers = Depends(get_current_active_user),
) -> Any:
    """
    批量获取地址信息
    
    Args:
        coordinates: 坐标列表，格式: [{"lat": 22.36, "lng": 114.256}, ...]
    """
    # 获取地址解析API配置（使用独立的配置）
    address_config = api_config.get_by_code(db, code="gpsAddressApi")
    if not address_config:
        return error_response(
            code=404,
            message="未找到GPS地址解析API配置，请联系管理员配置"
        )
    
    if not coordinates or len(coordinates) == 0:
        return error_response(
            code=400,
            message="坐标列表不能为空"
        )
    
    if len(coordinates) > 50:  # 限制批量查询数量
        return error_response(
            code=400,
            message="单次批量查询最多支持50个坐标点"
        )
    
    try:
        # 创建地址解析服务实例（使用地址解析专用配置）
        address_service = GPSAddressService(
            api_url=address_config.api_url,
            api_user=address_config.api_user,
            api_pwd=address_config.api_pwd
        )
        
        # 批量获取地址
        results = address_service.batch_get_addresses(coordinates)
        
        return {
            'total': len(results),
            'addresses': results
        }
        
    except Exception as e:
        logger.error(f"批量获取地址失败: {str(e)}")
        return error_response(
            code=500,
            message=f"批量获取地址失败: {str(e)}"
        )